/**
 *   Copyright 2014 Royce Remulla
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package cjcast.y2008.problem;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cjcast.common.AbstractSolution;

/**
 * 
 * Problem
 * 
 * The decimal numeral system is composed of ten digits, which we represent as
 * "0123456789" (the digits in a system are written from lowest to highest).
 * Imagine you have discovered an alien numeral system composed of some number
 * of digits, which may or may not be the same as those used in decimal. For
 * example, if the alien numeral system were represented as "oF8", then the
 * numbers one through ten would be (F, 8, Fo, FF, F8, 8o, 8F, 88, Foo, FoF). We
 * would like to be able to work with numbers in arbitrary alien systems. More
 * generally, we want to be able to convert an arbitrary number that's written
 * in one alien system into a second alien system.
 * 
 * Input
 * 
 * The first line of input gives the number of cases, N. N test cases follow.
 * Each case is a line formatted as
 * 
 * alien_number source_language target_language
 * 
 * Each language will be represented by a list of its digits, ordered from
 * lowest to highest value. No digit will be repeated in any representation, all
 * digits in the alien number will be present in the source language, and the
 * first digit of the alien number will not be the lowest valued digit of the
 * source language (in other words, the alien numbers have no leading zeroes).
 * Each digit will either be a number 0-9, an uppercase or lowercase letter, or
 * one of the following symbols !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
 * 
 * Output
 * 
 * For each test case, output one line containing "Case #x: " followed by the
 * alien number translated from the source language to the target language.
 * 
 * Limits
 * 
 * 1 ≤ N ≤ 100.
 * 
 * Small dataset
 * 
 * 1 ≤ num digits in alien_number ≤ 4, 2 ≤ num digits in source_language
 * ≤ 16, 2 ≤ num digits in target_language ≤ 16.
 * 
 * Large dataset
 * 
 * 1 ≤ alien_number (in decimal) ≤ 1000000000, 2 ≤ num digits in
 * source_language ≤ 94, 2 ≤ num digits in target_language ≤ 94.
 * 
 * Sample
 * 
 * Input
 * 
 * Output 4 9 0123456789 oF8 Foo oF8 0123456789 13 0123456789abcdef 01 CODE
 * O!CDE? A?JM!.
 * 
 * <pre>
 * $Author: royce.com@gmail.com $ 
 * $Date: 2015-02-03 03:44:46 +0000 (Tue, 03 Feb 2015) $
 * </pre>
 * 
 * @author Royce Remulla
 */

public class AlienNumber extends AbstractSolution<AlienNumberBean> {


    /** Case Size. */
    public static final int CASE_UNIT_SIZE = 1;


    /** {@inheritDoc} */
    @Override
    public String solve(final AlienNumberBean caseBean)
    {
        final char[] srcArray = caseBean.getSource().toCharArray();
        final Map<Character, Integer> sourceMap = new HashMap<Character, Integer>();
        for (int i = 0; i < srcArray.length; i++) {
            sourceMap.put(srcArray[i], i);
        }

        final char[] actualArr = caseBean.getAlienNumber().toCharArray();
        final char[] reverseArr = reverse(actualArr);

        long actual = computeActualValue(srcArray, sourceMap, reverseArr);

        final List<Character> result = new ArrayList<Character>();
        while (actual > 0) {
            final char[] tgtArray = caseBean.getTarget().toCharArray();
            final int remainder = (int) (actual % tgtArray.length);
            result.add(tgtArray[remainder]);
            actual /= tgtArray.length;
        }

        Collections.reverse(result);

        return charListToStr(result);
    }

    /**
     * @param srcArray
     * @param sourceMap
     * @param reverseArr
     */
    @SuppressWarnings("PMD.UseVarargs")
    long computeActualValue(final char[] srcArray,
            final Map<Character, Integer> sourceMap, final char[] reverseArr)
    {
        long actual = 0;
        for (int i = 0; i < reverseArr.length; i++) {
            actual += (long) (sourceMap.get(reverseArr[i]) * Double
                .valueOf(Math.pow(srcArray.length, i)));
        }
        return actual;
    }

    String charListToStr(final List<Character> list)
    {
        final StringBuilder builder = new StringBuilder(list.size());
        for (final Character chr : list) {
            builder.append(chr);
        }
        return builder.toString();
    }


    /**
     * @param actualArr
     * @return
     */
    @SuppressWarnings("PMD.DataflowAnomalyAnalysis")
    private char[] reverse(final char... actualArr)
    {
        final char[] retval = new char[actualArr.length];
        for (int i = 0; i < actualArr.length; i++) {
            retval[actualArr.length - i - 1] = actualArr[i];
        }
        return retval;
    }

    /**
     * This will generate contents of output file for submission.
     * 
     * @param args command line arguments.
     * 
     * @throws IOException if error occurs while parsing the file.
     */
    public static void main(final String... args) throws IOException
    {
        final AlienNumber alienNumCase = new AlienNumber();
        alienNumCase.execute("c:\\");
    }


    /** {@inheritDoc} */
    @Override
    protected int getCaseUnitSize()
    {
        return CASE_UNIT_SIZE;
    }


    /** {@inheritDoc} */
    @Override
    protected AlienNumberBean parseInputLines(final String... input)
    {
        final String[] oneLine = input[0].split(" ");
        return new AlienNumberBean(

        oneLine[0], oneLine[1], oneLine[2]);
    }

}